#include <func.h>

#define MMAP_SIZE (4096 * 10)

int main(int argc, char* argv[])
{
	// ./mmap_cp src dst
	if (argc != 3) {
		error(1, 0, "%s src dst", argv[0]);
	}

	// 1. 打开文件
	int srcfd = open(argv[1], O_RDONLY);
	if (srcfd == -1) {
		error(1, errno, "open %s", argv[1]);
	}

	int dstfd = open(argv[2], O_RDWR | O_CREAT | O_TRUNC, 0666);
	if (dstfd == -1) {
		error(1, errno, "open %s", argv[2]);
	}

	// 2. 先固定目的地文件的大小
	struct stat sb;
	if(fstat(srcfd, &sb) == -1) {
		error(1, errno, "fstat %s", argv[1]);
	}

	off_t fsize = sb.st_size;
	if (ftruncate(dstfd, fsize) == -1) {
		error(1, errno, "ftruncate %s", argv[2]);
	}

	// 3. 复制
	off_t offset = 0; // 已复制的大小
	while (offset < fsize) {
		off_t length = (fsize - offset) >= MMAP_SIZE ? 
			MMAP_SIZE : (fsize - offset);
		
		void* addr1 = mmap(NULL, length, PROT_READ, MAP_SHARED, srcfd, offset);
		if (addr1 == MAP_FAILED) {
			error(1, errno, "mmap %s", argv[1]);
		}
		void* addr2 = mmap(NULL, length, PROT_READ | PROT_WRITE, MAP_SHARED, dstfd, offset);
		if (addr2 == MAP_FAILED) {
			error(1, errno, "mmap %s", argv[2]);
		}

		// 使用操作内存的函数，进行读写文件
		memcpy(addr2, addr1, length);
		offset += length;

		munmap(addr1, length);
		munmap(addr2, length);

	} // offset == fsize
	
	// 4. 关闭文件
	close(srcfd);
	close(dstfd);
    return 0;
}

